use chrono::Timelike;
use serde::{Deserialize, Serialize};
use serde_json::{Map, Number, Value};
use std::{borrow::Borrow, str::FromStr};
use wither::bson::{oid::ObjectId, to_bson, Bson, Document, Regex};

use super::strings::text_cut_for_search;

/// 构造查询的正则选项默认值
static BUILD_WHERE_REGEXP_OPTIONS: &str = "p";
static OID_KEY: &str = "$oid";
static SEARCH_KEY: &str = "$search";
pub static COMMON_NO_REGEXP: [&str; 2] = ["created_at", "updated_at"];
pub static DISABLED_OPERATOR: [&str; 3] = ["$where", "$expr", "$function"];
const QUERY_STURCT_MAX_DEEP: usize = 100;
#[derive(Debug, Clone, Serialize, Deserialize)]

/// ## SearchJson
/// 工具结构体，实现了`Into<Option<Document>>`内部调用`build_filter(&self.0,&COMMON_NO_REGEXP)`
pub struct SearchJson(Value);
impl From<&SearchJson> for Option<Document> {
    fn from(s: &SearchJson) -> Self {
        build_filter(&s.0, &COMMON_NO_REGEXP)
    }
}

/// ## DocJson
/// 工具结构体，实现了`Into<Option<Document>>`内部调用`json_to_document(&self.0)`
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DocJson(Value);

impl From<&DocJson> for Option<Document> {
    fn from(d: &DocJson) -> Self {
        json_to_document(&d.0)
    }
}

#[inline]
fn oid_object(json_map: &Map<String, Value>) -> Option<ObjectId> {
    if json_map.len() != 1 {
        return None;
    }
    if let Some(Value::String(s)) = json_map.get(OID_KEY) {
        if let Ok(oid) = ObjectId::from_str(s) {
            return Some(oid);
        }
    }
    None
}

pub fn json_to_bson(json_val: &Value) -> Bson {
    json_to_bson_impl(json_val, 0)
}
fn json_to_bson_impl(json_val: &Value, deep: usize) -> Bson {
    if deep > QUERY_STURCT_MAX_DEEP {
        return Bson::Null;
    }
    match json_val {
        Value::Bool(bool_val) => Bson::Boolean(*bool_val),
        Value::String(str_val) => Bson::String(str_val.to_owned()),
        Value::Number(num_val) => {
            if num_val.is_f64() {
                num_val.as_f64().into()
            } else {
                num_val.as_i64().into()
            }
        }
        Value::Array(arr) => arr
            .iter()
            .map(|v| json_to_bson_impl(v, deep + 1))
            .collect::<Vec<_>>()
            .into(),
        Value::Object(obj_value) => {
            if let Some(oid) = oid_object(&*obj_value) {
                return Bson::ObjectId(oid);
            }
            obj_value
                .iter()
                .map(|(key, value)| (key.clone(), json_to_bson_impl(value, deep + 1)))
                .collect::<Document>()
                .into()
        }
        _ => Bson::Null,
    }
}
pub fn json_to_document(json_value: &Value) -> Option<Document> {
    match json_value {
        Value::Object(o) => Some(
            o.iter()
                .map(|(key, value)| (key.clone(), json_to_bson(value)))
                .collect::<Document>(),
        ),
        _ => None,
    }
}

/// ## build_filter
/// 构造mdb的查询过滤参数
/// `no_regexp_key` 默认字符串都是正则形式，非正则key需要在no_regexp_keys单独给出
pub fn build_filter(where_value: &Value, no_regexp_keys: &[&str]) -> Option<Document> {
    build_filter_impl(where_value, no_regexp_keys, 0)
}

fn build_filter_impl(
    where_value: &Value,
    no_regexp_keys: &[&str],
    deep: usize,
) -> Option<Document> {
    if deep > QUERY_STURCT_MAX_DEEP {
        return None;
    }
    match where_value {
        Value::Object(obj_value) => {
            let mut doc = Document::new();
            for (key, item) in obj_value {
                if DISABLED_OPERATOR.contains(&key.as_str()) {
                    // 禁用的操作符直接跳过
                    continue;
                }
                match item {
                    Value::String(str_val) => {
                        if no_regexp_keys.contains(&str_val.as_str()) {
                            doc.insert(key, str_val);
                            continue;
                        }
                        if key == SEARCH_KEY {
                            doc.insert(key, text_cut_for_search(str_val));
                            continue;
                        }
                        doc.insert(
                            key,
                            Bson::RegularExpression(Regex {
                                pattern: str_val.clone(),
                                options: BUILD_WHERE_REGEXP_OPTIONS.to_string(),
                            }),
                        );
                    }
                    Value::Bool(bool_val) => {
                        doc.insert(key, bool_val);
                    }
                    Value::Array(arr_val) => {
                        doc.insert(
                            key,
                            arr_val
                                .iter()
                                .filter_map(|v| build_filter_impl(v, no_regexp_keys, deep + 1))
                                .collect::<Vec<_>>(),
                        );
                    }
                    Value::Number(num_val) => {
                        if num_val.is_f64() {
                            doc.insert(key, num_val.as_f64());
                        } else {
                            // mongo中没有u64类型，如果直接传u64可能会出现未定义的行为
                            doc.insert(key, num_val.as_i64());
                        }
                    }
                    Value::Null => {
                        doc.insert(key, Bson::Null);
                    }
                    Value::Object(obj_value) => {
                        if let Some(oid) = oid_object(obj_value) {
                            doc.insert(key, oid);
                            continue;
                        }
                        doc.insert(key, build_filter_impl(item, no_regexp_keys, deep + 1));
                    }
                }
            }
            Some(doc)
        }
        _ => None,
    }
}

pub fn bson_to_json(bs: &Bson) -> Value {
    match bs {
        Bson::Array(a) => {
            let a = a.iter().map(bson_to_json).collect::<Vec<_>>();
            Value::Array(a)
        }
        Bson::Binary(binary) => Value::Array(
            binary
                .bytes
                .iter()
                .map(|v| Value::Number((*v).into()))
                .collect::<Vec<_>>(),
        ),
        Bson::String(s) => Value::String(s.clone()),
        Bson::Boolean(b) => Value::Bool(*b),
        Bson::Double(d) => Value::Number(Number::from_f64(*d).unwrap_or_else(|| 0.into())),
        Bson::Int32(i) => Value::Number((*i).into()),
        Bson::Int64(i) => Value::Number((*i).into()),
        Bson::ObjectId(oid) => Value::String(oid.to_string()),
        Bson::DateTime(dt) => Value::String(dt.to_chrono().to_string()),
        Bson::Timestamp(ts) => Value::Number(
            (((ts.time.to_le().overflowing_shl(32).0) as u64) | (ts.increment as u64)).into(),
        ),
        Bson::RegularExpression(re) => Value::String(re.pattern.clone()),
        Bson::Symbol(s) => Value::String(s.clone()),
        Bson::Undefined => Value::Null,
        Bson::Document(d) => Value::Object(
            d.iter()
                .map(|(key, value)| (key.clone(), bson_to_json(value)))
                .collect::<Map<String, Value>>(),
        ),
        Bson::Null => Value::Null,
        _ => Value::Null,
    }
}
/// ## 更新请求中的字段
/// 这个字段可以设置不改变，取消设置和更新数据
/// 基本满足所有更新操作
#[derive(Debug, Serialize, Deserialize)]
pub enum UpdateField<T> {
    #[serde(rename = "unchanged")]
    Unchanged,
    #[serde(rename = "unset")]
    Unset,
    #[serde(rename = "set")]
    Set(T),
}
impl<T> Default for UpdateField<T> {
    fn default() -> Self {
        Self::Unchanged
    }
}

impl<T> Clone for UpdateField<T>
where
    T: Clone,
{
    fn clone(&self) -> Self {
        match self {
            Self::Unchanged => Self::Unchanged,
            Self::Unset => Self::Unset,
            Self::Set(t) => Self::Set(t.clone()),
        }
    }
}
impl<T> UpdateField<T>
where
    T: Serialize,
{
    #[inline]
    pub fn to_bson(&self) -> wither::bson::ser::Result<Option<Bson>> {
        match self {
            Self::Unchanged => Ok(None),
            Self::Unset => Ok(Some(Bson::Null)),
            Self::Set(val) => to_bson(val).map(Option::Some),
        }
    }
}

impl<T> UpdateField<T> {
    #[inline]
    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> UpdateField<U> {
        match self {
            Self::Unchanged => UpdateField::Unchanged,
            Self::Unset => UpdateField::Unset,
            Self::Set(x) => UpdateField::Set(f(x)),
        }
    }
    pub fn as_ref(&self) -> UpdateField<&T> {
        match *self {
            UpdateField::Unchanged => UpdateField::Unchanged,
            UpdateField::Unset => UpdateField::Unset,
            UpdateField::Set(ref v) => UpdateField::Set(v),
        }
    }
    #[inline]
    pub fn is_unchanged(&self) -> bool {
        matches!(*self, UpdateField::Unchanged)
    }
    #[inline]
    pub fn is_unset(&self) -> bool {
        matches!(*self, UpdateField::Unset)
    }
    #[inline]
    pub fn is_set(&self) -> bool {
        matches!(*self, UpdateField::Set(_))
    }
}

impl<T> UpdateField<UpdateField<T>> {
    pub fn flatten(self) -> UpdateField<T> {
        match self {
            UpdateField::Unchanged => UpdateField::Unchanged,
            UpdateField::Unset => UpdateField::Unset,
            UpdateField::Set(inner) => inner,
        }
    }
}

/// ## 将输入的时间设置为当天的最后一秒
/// 如下代码为获得当天的最后一秒
/// ```rust
/// use shimmer_club::utils::db_utils::*;
/// let last_second = fixed_time_to_last_second(chrono::Utc::now(), chrono::FixedOffset::east(8 * 3600));
/// ```
pub fn fixed_time_to_last_second<T: chrono::TimeZone, O: chrono::TimeZone, I: Borrow<O>>(
    time: chrono::DateTime<T>,
    time_zone: I,
) -> chrono::DateTime<O> {
    let now = time.with_timezone(time_zone.borrow());
    now.with_hour(23)
        .unwrap()
        .with_minute(59)
        .unwrap()
        .with_second(59)
        .unwrap()
        .with_nanosecond(0)
        .unwrap()
}
